import json
from os import remove
from bpy.types import Operator
from bpy.props import StringProperty
from os.path import join, isfile, exists
from ...addon.naming import FluidLabPaths
# from ...addon.naming import FluidLabNaming
from ...libs.functions.libraries import read_fluid_preset
from ...libs.functions.get_common_vars import get_common_vars
from ...libs.functions.common_ui_elements import multiline_print



def set_properties(fluid_presets, data:dict) -> None:
    for prop in data.keys():
        data[prop] = getattr(fluid_presets, prop)


class FLUIDLAB_OT_fluid_presets(Operator):
    bl_idname = "fluidlab.fluid_presets_set"
    bl_label = "Set Fluid Presets"
    bl_description = "Fluid Presets set"
    bl_options = {"REGISTER", "UNDO"}

    
    def execute(self, context):
        
        fluid_groups = get_common_vars(context, get_fluid_groups=True)
        active_group = fluid_groups.active
        
        if not active_group:
            print("No active group, cancelled!")
            return {'CANCELLED'}

        all_emitter_items = active_group.emitters.get_all_items
        
        if not all_emitter_items:
            print("No emitters items avalidable, cancelled!")
            return  {'CANCELLED'}
        
        default_path = join(FluidLabPaths.LIBS, "fluid_presets")
        fluid_presets = get_common_vars(context, get_fluid_presets=True)

        filename = fluid_presets.presets.lower() + ".json"
        file = join(default_path, filename)

        emission_data = read_fluid_preset(context, filename, file, "emission_props")
        physics_data = read_fluid_preset(context, filename, file, "physics_props")
        springs_data = read_fluid_preset(context, filename, file, "springs_props")
        
        if physics_data is None and springs_data is None:
            print("No data, cancelled!")
            return  {'CANCELLED'}


        def set_properties(data_dic, props):
            # Seteamos las propiedades reales con los valores del json:
            for slug, value in data_dic.items():
                setattr(props, slug, value)

        for item in all_emitter_items:
            set_properties(emission_data, item.emission)
            set_properties(physics_data, item.physics)
            set_properties(springs_data, item.springs)
        
        return {'FINISHED'}


class FLUIDLAB_OT_fluid_preset_remove(Operator):
    bl_idname = "fluidlab.fluid_preset_remove"
    bl_label = "Remove Fluid Preset"
    bl_description = "Remove Fluid Preset"
    bl_options = {"REGISTER", "UNDO"}


    def invoke(self, context, event):
        return context.window_manager.invoke_props_dialog(self, width=250)
    

    def draw(self, context):
        layout = self.layout
        layout.use_property_decorate = False
        layout.use_property_split = False

        fluid_presets = get_common_vars(context, get_fluid_presets=True)
        target = fluid_presets.presets.title()

        text=f"You are going to remove the \"{target}\" preset. Are you sure?"
        multiline_print(layout, text, 6, 'INFO')

    
    def execute(self, context):
        
        default_path = join(FluidLabPaths.LIBS, "fluid_presets")
        fluid_presets = get_common_vars(context, get_fluid_presets=True)

        basename = fluid_presets.presets.lower()
        filename = basename + ".json"
        file = join(default_path, filename)

        if not exists(file):
            print(f"[fluidlab.fluid_preset_remove] File {file} dont exist!")
            return {'CANCELLED'}

        print(f"[fluidlab.fluid_preset_remove] Remove {file}")

        # capturo el item del dropdown:
        item = next((item for item in fluid_presets.items if item[0].lower() == basename), None)
        if item:

            # Lo tuitamos de los items disponibles:
            fluid_presets.items.remove(item)

        # borramos el archivo:
        remove(file)

        # seteamos al dropdown el ultimo elemento disponible
        fluid_presets.presets = fluid_presets.items[-1][0]

        # notificamos:
        self.report({'INFO'}, f"Preset {filename} has been removed")

        return {'FINISHED'}

class FLUIDLAB_OT_fluid_save_preset(Operator):
    bl_idname = "fluidlab.fluid_save_presets"
    bl_label = "Save Preset"
    bl_description = "Save Fluid Presets"
    bl_options = {"REGISTER", "UNDO"}


    def invoke(self, context, event):
        return context.window_manager.invoke_props_dialog(self, width=250)
    

    def draw(self, context):
        layout = self.layout
        layout.use_property_decorate = False
        layout.use_property_split = False

        fluid_presets = get_common_vars(context, get_fluid_presets=True)
        target = fluid_presets.presets.title()

        text=f"You are going to overwrite the \"{target}\" preset. Are you sure?"
        multiline_print(layout, text, 6, 'INFO')

    
    def execute(self, context):

        default_path = join(FluidLabPaths.LIBS, "fluid_presets")
        fluid_presets = get_common_vars(context, get_fluid_presets=True)

        filename = fluid_presets.presets.lower() + ".json"
        file = join(default_path, filename)

        # Abrir el archivo JSON y cargarlo en un diccionario
        with open(file, 'r') as f:
            data = json.load(f)
        
        # Emission_props:
        emission_props = data["emission_props"]
        set_properties(fluid_presets, emission_props)

        # Physics_props:
        physics_props = data["physics_props"]
        set_properties(fluid_presets, physics_props)
        
        # Springs_props:
        springs_props = data["springs_props"]
        set_properties(fluid_presets, springs_props)

        # Escribir el diccionario modificado de vuelta al archivo JSON
        with open(file, 'w') as f:
            json.dump(data, f, indent=4)
        
        # Terminamos de editar
        fluid_presets.edit_preset = False

        # fuerzo la lectura del preset.json en lugar de el que esta guardado en wm (porque si fue editado, no se reflejará)
        wm = context.window_manager
        if filename in wm:
            del wm[filename]
        
        print(f"[fluid_save_presets] Save preset {filename}!")
        
        return {'FINISHED'}


class FLUIDLAB_OT_fluid_new_preset(Operator):
    bl_idname = "fluidlab.fluid_new_preset"
    bl_label = "New Preset"
    bl_description = "New Fluid Preset"
    bl_options = {"REGISTER", "UNDO"}

    new_name: StringProperty(name="Name", description="New Preset Name")


    def invoke(self, context, event):
        return context.window_manager.invoke_props_dialog(self, width=250)


    def draw(self, context):
        layout = self.layout
        layout.use_property_decorate = False
        layout.use_property_split = False

        layout.prop(self, "new_name", text="Name")


    def execute(self, context):

        default_path = join(FluidLabPaths.LIBS, "fluid_presets")
        file = join(default_path, self.new_name.lower() + ".json")

        check_file = isfile(file)
        if check_file:
            self.report({'WARNING'}, f"{self.new_name} already exist!")
            return {'CANCELLED'}

        fluid_presets = get_common_vars(context, get_fluid_presets=True)

        # Preset Base:
        # Recopilamos los datos seteados del active emitter actual:
        fluid_groups = get_common_vars(context, get_fluid_groups=True)
        active_group = fluid_groups.active
        active_emitter = active_group.emitters.active

        emission_props = active_emitter.emission
        physics_props = active_emitter.physics
        springs_props = active_emitter.springs

        data = {
            "id_name": self.new_name.upper(),
            "name": self.new_name.title(),
            "emission_props": {
                "size_random": emission_props.size_random 
            },
            "physics_props": {
                "timestep": physics_props.timestep,
                "subframes": physics_props.subframes,
                "use_adaptive_subframes": physics_props.use_adaptive_subframes,
                "courant_target": physics_props.courant_target,
                "mass": physics_props.mass,
                "use_multiply_size_mass": physics_props.use_multiply_size_mass,
                "stiffness": physics_props.stiffness,
                "linear_viscosity": physics_props.linear_viscosity,
                "drag_factor": physics_props.drag_factor,
                "damping": physics_props.damping,
                "use_size_deflect": physics_props.use_size_deflect,
                "repulsion": physics_props.repulsion,
                "stiff_viscosity": physics_props.stiff_viscosity,
                "fluid_radius": physics_props.fluid_radius,
                "rest_density": physics_props.rest_density
            },
            "springs_props": {
                "spring_force": springs_props.spring_force,
                "use_viscoelastic_springs": springs_props.use_viscoelastic_springs,
                "yield_ratio": springs_props.yield_ratio,
                "plasticity": springs_props.plasticity,
                "use_initial_rest_length": springs_props.use_initial_rest_length,
                "spring_frames": springs_props.spring_frames,
                "use_factor_rest_length": springs_props.use_factor_rest_length,
                "rest_length": springs_props.rest_length
            }
        }

        # Lo guardamos en el archivo:
        with open(file, 'w') as f:
            json.dump(data, f, indent=4)
        
        # Agrego el nuevo item al listado de items:
        item = (self.new_name.upper(), self.new_name.title(), "")
        if item not in fluid_presets.items:
            fluid_presets.items.append(item)
            fluid_presets.presets = self.new_name.upper()

        return {'FINISHED'}